package cn.example.util.toolkit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

/**
 * 日期时间工具类
 * Created by WuYB on 2017/3/10.
 */
public class DateUtil {

    private static final Logger log = LoggerFactory.getLogger(DateUtil.class);

    private static class SingletonHolder {
        private static final DateUtil INSTANCE = new DateUtil();
    }

    private DateUtil() {
    }

    public static DateUtil getInstance() {
        return SingletonHolder.INSTANCE;
    }

    /**
     * 日期转化为字符串
     *
     * @param date   日期
     * @param format 日期格式
     * @return String
     */
    public String date2Str(Date date, String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(date);
    }

    /**
     * 日期转化为ISO8601标准时间字符串
     *
     * @param date 日期
     * @return String
     */
    public String date2StrISO8601(Date date) {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
        df.setTimeZone(TimeZone.getTimeZone("UTC"));
        return df.format(date);
    }

    /**
     * ISO8601标准时间字符串转化为日期
     *
     * @param iso8601Str ISO8601标准时间字符串
     * @return Date
     */
    public Date strISO8601Date(String iso8601Str) {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
        df.setTimeZone(TimeZone.getTimeZone("UTC"));
        try {
            return df.parse(iso8601Str);
        } catch (ParseException e) {
            log.error("ISO8601 Date Parse Error!", e);
            return new Date();
        }
    }

    /**
     * 字符串转化为日期型
     *
     * @param myDate 需要转化为日期的字符串
     * @param format 日期格式
     * @return Date
     */
    public Date str2Date(String myDate, String format) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(format);
            return sdf.parse(myDate);
        } catch (ParseException e) {
            log.error("Date Parse Error!", e);
            return new Date();
        }
    }

    /**
     * 日期判断是否为周末
     *
     * @param date 日期
     * @return boolean
     */
    public boolean isWeekend(Date date) {
        Calendar cal = getCalender(date);
        return cal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY || cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY;
    }

    /**
     * 比较日期（精确到天）
     *
     * @param date1 日期1
     * @param date2 日期2
     * @return int
     */
    public int compareDate(Date date1, Date date2) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String Date1 = sdf.format(date1);
        String Date2 = sdf.format(date2);
        if (Date1.compareTo(Date2) == 0) {
            return 0;
        } else if (Date1.compareTo(Date2) > 0) {
            /*Date1>Date2*/
            return 1;
        } else {
            /*Date1<Date2*/
            return -1;
        }
    }

    /**
     * 日期增加天数
     *
     * @param date 日期
     * @param days 天数
     * @return Date
     */
    public Date nextDay(Date date, int days) {
        Calendar c = getCalender(date);
        c.set(Calendar.DATE, c.get(Calendar.DATE) + days);
        return c.getTime();
    }

    /**
     * 计算日期间隔天数
     *
     * @param start 开始日期
     * @param end   结束日期
     * @return int
     */
    public int dayInterval(Date start, Date end) {
        start = getDayStart(start);
        end = getDayStart(end);
        return (int) (msInterval(start, end) / (24 * 3600 * 1000));
    }

    /**
     * 计算日期间隔毫秒数
     *
     * @param start 开始日期
     * @param end   结束日期
     * @return int
     */
    public long msInterval(Date start, Date end) {
        return end.getTime() - start.getTime();
    }

    /**
     * 获取某天0：00：00
     *
     * @param date 时间
     * @return Date
     */
    public Date getDayStart(Date date) {
        Calendar calendar = getCalender(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    /**
     * 获取某天23：59：59
     *
     * @param date 时间
     * @return Date
     */
    public Date getDayEnd(Date date) {
        Calendar calendar = getCalender(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        calendar.add(Calendar.SECOND, -1);
        return calendar.getTime();
    }

    /**
     * 获取某周第一天0：00：00
     *
     * @param date 时间
     * @return Date
     */
    public Date getWeekStart(Date date) {
        Calendar cDate = Calendar.getInstance();
        cDate.setFirstDayOfWeek(Calendar.SUNDAY);
        cDate.setTime(date);
        Calendar calendar = Calendar.getInstance();
        calendar.setFirstDayOfWeek(Calendar.SUNDAY);
        calendar.setTime(date);
        if (cDate.get(Calendar.WEEK_OF_YEAR) == Calendar.SUNDAY && cDate.get(Calendar.MONTH) == Calendar.DECEMBER) {
            calendar.set(Calendar.YEAR, cDate.get(Calendar.YEAR) + 1);
        }
        int typeNum = cDate.get(Calendar.WEEK_OF_YEAR);
        calendar.set(Calendar.WEEK_OF_YEAR, typeNum);
        calendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
        return getDayStart(calendar.getTime());
    }

    /**
     * 获取某周最后一天23：59：59
     *
     * @param date 时间
     * @return Date
     */
    public Date getWeekEnd(Date date) {
        Calendar cDate = getCalender(date);
        cDate.setFirstDayOfWeek(Calendar.SUNDAY);
        Calendar calendar = getCalender(date);
        calendar.setFirstDayOfWeek(Calendar.SUNDAY);
        if (cDate.get(Calendar.WEEK_OF_YEAR) == Calendar.SUNDAY && cDate.get(Calendar.MONTH) == Calendar.DECEMBER) {
            calendar.set(Calendar.YEAR, cDate.get(Calendar.YEAR) + 1);
        }
        int typeNum = cDate.get(Calendar.WEEK_OF_YEAR);//当前周数
        calendar.set(Calendar.WEEK_OF_YEAR, typeNum);
        calendar.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);
        return getDayEnd(calendar.getTime());
    }

    /**
     * 获取某月第一天0：00：00
     *
     * @param date 时间
     * @return Date
     */
    public Date getMonthStart(Date date) {
        Calendar calendar = getCalender(date);
        calendar.add(Calendar.MONTH, 0);
        calendar.set(Calendar.DAY_OF_MONTH, 1);//设置为1号,当前日期既为本月第一天
        return getDayStart(calendar.getTime());
    }

    /**
     * 获取某月最后一天23：59：59
     *
     * @param date 时间
     * @return Date
     */
    public Date getMonthEnd(Date date) {
        Calendar calendar = getCalender(date);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));

        return getDayEnd(calendar.getTime());
    }

    /**
     * 获取某季度第一天0：00：00
     *
     * @param date 时间
     * @return Date
     */
    public Date getSeasonStart(Date date) {
        Calendar calendar = getCalender(date);
        int curMonth = calendar.get(Calendar.MONTH);
        if (curMonth >= Calendar.JANUARY && curMonth <= Calendar.MARCH) {
            calendar.set(Calendar.MONTH, Calendar.JANUARY);
        }
        if (curMonth >= Calendar.APRIL && curMonth <= Calendar.JUNE) {
            calendar.set(Calendar.MONTH, Calendar.APRIL);
        }
        if (curMonth >= Calendar.JULY && curMonth <= Calendar.SEPTEMBER) {
            calendar.set(Calendar.MONTH, Calendar.JULY);
        }
        if (curMonth >= Calendar.OCTOBER && curMonth <= Calendar.DECEMBER) {
            calendar.set(Calendar.MONTH, Calendar.OCTOBER);
        }
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));

        return getDayStart(calendar.getTime());
    }

    /**
     * 获取某月最后一天23：59：59
     *
     * @param date 时间
     * @return Date
     */
    public Date getSeasonEnd(Date date) {
        Calendar calendar = getCalender(date);
        int curMonth = calendar.get(Calendar.MONTH);
        if (curMonth >= Calendar.JANUARY && curMonth <= Calendar.MARCH) {
            calendar.set(Calendar.MONTH, Calendar.MARCH);
        }
        if (curMonth >= Calendar.APRIL && curMonth <= Calendar.JUNE) {
            calendar.set(Calendar.MONTH, Calendar.JUNE);
        }
        if (curMonth >= Calendar.JULY && curMonth <= Calendar.SEPTEMBER) {
            calendar.set(Calendar.MONTH, Calendar.SEPTEMBER);
        }
        if (curMonth >= Calendar.OCTOBER && curMonth <= Calendar.DECEMBER) {
            calendar.set(Calendar.MONTH, Calendar.DECEMBER);
        }
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        return getDayEnd(calendar.getTime());
    }

    /**
     * 获取某年第一天0：00：00
     *
     * @param date 时间
     * @return Date
     */
    public Date getYearStart(Date date) {
        Calendar calendar = getCalender(date);
        int year = calendar.get(Calendar.YEAR);
        calendar.clear();
        calendar.set(Calendar.YEAR, year);
        return getDayStart(calendar.getTime());
    }

    /**
     * 获取某年最后一天23：59：59
     *
     * @param date 时间
     * @return Date
     */
    public Date getYearEnd(Date date) {
        Calendar calendar = getCalender(date);
        int year = calendar.get(Calendar.YEAR);
        calendar.clear();
        calendar.clear();
        calendar.set(Calendar.YEAR, year);
        calendar.roll(Calendar.DAY_OF_YEAR, -1);
        return getDayEnd(calendar.getTime());
    }

    /**
     * 获得上一季度时间
     *
     * @param date 当前时间
     * @return Date
     */
    public Date getLastSeason(Date date) {
        Calendar calendar = getCalender(date);
        calendar.add(Calendar.MONTH, -3);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        return calendar.getTime();
    }

    /**
     * 获取日期年份
     *
     * @param date Date
     * @return int
     */
    public int getDateYear(Date date) {
        Calendar cd = getCalender(date);
        return cd.get(Calendar.YEAR);
    }

    /**
     * 获取日期月份
     *
     * @param date Date
     * @return int
     */
    public int getDateMonth(Date date) {
        Calendar cd = getCalender(date);
        return cd.get(Calendar.MONTH) + 1;
    }

    /**
     * 获取日期当月天数
     *
     * @param date Date
     * @return int
     */
    public int getDateDay(Date date) {
        Calendar cd = getCalender(date);
        return cd.get(Calendar.DAY_OF_MONTH);
    }

    /**
     * 初始化Calendar
     *
     * @param date Date
     * @return Calendar
     */
    private Calendar getCalender(Date date) {
        Calendar cd = Calendar.getInstance();
        if (date != null) {
            cd.setTime(date);
        }
        return cd;
    }

}

